﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;

namespace org.EDS
{
    public class Server
    {
        private bool canStart;

        private int _Block;

        private int _BufferSize;

        private Socket _sock;

        private int _Port;

        private ManualResetEvent Done = new ManualResetEvent(false);

        public event ConnectHandler OnGetConnected;

        public event ReadHandler OnGetBytes;

        public event ReadFinishHandler OnReadDone;

        public Server(int Port, int BlockLen, int BufferSize)
        {
            _Port = Port;
            _Block = BlockLen;
            _BufferSize = BufferSize;
            _sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
        }

        public void Start()
        {
            Done.Reset();
            canStart = true;
            _sock.Bind(
                new IPEndPoint(
                    IPAddress.Any, _Port)
                    );
            _sock.Listen(_Block);
            ThreadPool.QueueUserWorkItem(new WaitCallback(Loop), _sock);
            Done.WaitOne();
        }

        public void Close()
        {
            this.canStart = false;
        }
        private void Loop(object state)
        {
            Socket sock = (Socket)state;
            while (canStart)
            {
                Done.Reset();
                sock.BeginAccept(new AsyncCallback(AcceptSocket), sock);
                Done.WaitOne();
            }
        }

        private void AcceptSocket(IAsyncResult Ar)
        {
            Done.Set();
            Socket sock = (Socket)Ar.AsyncState;
            Socket Handle = sock.EndAccept(Ar);
            ReadState rs = new ReadState(_BufferSize, Handle);
            if (OnGetConnected != null)
            {
                ConnectedState stu=new ConnectedState();
                stu.RemoteIP= ((IPEndPoint)Handle.RemoteEndPoint).Address.ToString();
                stu.RemotePort = ((IPEndPoint)Handle.RemoteEndPoint).Port;
                OnGetConnected(this, stu);
            }
            Handle.BeginReceive(rs.Buffer, 0, _BufferSize, SocketFlags.None, new AsyncCallback(Read), rs);
        }

        private void Read(IAsyncResult Ar)
        {
            ReadState state = (ReadState)Ar.AsyncState;
            Socket sock = state.WorkHandler;
            int ReadCount = sock.EndReceive(Ar);
            if (ReadCount == _BufferSize)
            {
                if (OnGetBytes != null)
                {
                    OnGetBytes(this, state);
                }
                if (OnReadDone != null)
                {
                    state.Stream.Write(state.Buffer, 0, _BufferSize);
                    state.Stream.Flush();
                }
                sock.BeginReceive(state.Buffer, 0, _BufferSize, SocketFlags.None, new AsyncCallback(Read), state);
            }
            else
            {
                if (ReadCount > 0)
                {
                    if (OnGetBytes != null)
                    {
                        OnGetBytes(this, state);
                    }
                    if (OnReadDone != null)
                    {
                        state.Stream.Write(state.Buffer, 0, ReadCount);
                        state.Stream.Flush();
                        OnReadDone(this, state);
                    }
                }
                else
                {
                    if (OnReadDone != null)
                    {
                        OnReadDone(this, state);
                    }
                }
            }
        }

    }
}
